using System;
using System.Collections.Generic;
using System.Text;

namespace Mud.Common
{

	public struct ResultWithReason
	{
		/// <summary>
		/// Gets a value indicating whether the result <see cref="ResultWithReason"/> is success.
		/// </summary>
		public bool Success
		{
			get { return _success; }
		}
		private bool _success;

		/// <summary>
		/// Gets the reason why something failed.
		/// </summary>
		public string FailReason
		{
			get { return _failReason; }
		}
		private string _failReason;

		/// <summary>
		/// Initializes a new instance of the <see cref="ResultWithReason"/> class.
		/// </summary>
		/// <param name="success">if set to <c>true</c> then the operation was success.</param>
		/// <param name="failReason">The reason why something failed.</param>
		public ResultWithReason(bool success, string failReason)
		{
			_success = success;
            if (!success && failReason == null)
                throw new ArgumentNullException(failReason);

			_failReason = failReason;
		}

		/// <summary>
		/// Gets the static instance of success reason.
		/// </summary>
		public static ResultWithReason Ok
		{
			get
			{
				return _ok;
			}
		}
		private static ResultWithReason _ok = new ResultWithReason(true, string.Empty);

		/// <summary>
		/// Creates failed result.
		/// </summary>
		/// <param name="why">Failure reason.</param>
		public static ResultWithReason Failed(string why)
		{
			return new ResultWithReason(false, why);
		}

        /// <summary>
        /// Creates failed result.
        /// </summary>
        /// <param name="why">Failure reason.</param>
        public static ResultWithReason Failed(string why, params string[] args)
        {
            return new ResultWithReason(false, string.Format(why, args));
        }

        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="left">The left.</param>
        /// <param name="right">The right.</param>
        /// <returns>The result of the operator.</returns>
        public static bool operator==(ResultWithReason left, ResultWithReason right) 
        {
            return left.Success == right.Success;
        }

        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="left">The left.</param>
        /// <param name="right">The right.</param>
        /// <returns>The result of the operator.</returns>
        public static bool operator !=(ResultWithReason left, ResultWithReason right)
        {
            return left.Success != right.Success;
        }

        /// <summary>
        /// Indicates whether this instance and a specified object are equal.
        /// </summary>
        /// <param name="obj">Another object to compare to.</param>
        /// <returns>
        /// true if obj and this instance are the same type and represent the same value; otherwise, false.
        /// </returns>
        public override bool Equals(object obj)
        {
            if (obj is ResultWithReason)
            {
                return this == (ResultWithReason)obj;
            }
            return false;
        }

        /// <summary>
        /// Returns the hash code for this instance.
        /// </summary>
        /// <returns>
        /// A 32-bit signed integer that is the hash code for this instance.
        /// </returns>
        public override int GetHashCode()
        {
            if (this._success)
                return this._success.GetHashCode();
            else
                return this._success.GetHashCode() ^ this._failReason.GetHashCode();
        }

        /// <summary>
        /// Wraps the result into a message.
        /// </summary>
        /// <param name="reason">The result.</param>
        public static Mud.Common.Messages.IMessage WrapMessage(ResultWithReason reason)
        {
            if (reason.Success)
                return Mud.Common.Messages.MessageResponseOk.Instance;
            else
                return new Mud.Common.Messages.MessageResponseError(reason.FailReason);
        }

	}
}
